package com.apps.shelper;


import com.apps.shelper.enums.ClassType;
import com.baomidou.mybatisplus.annotation.TableName;
import com.apps.sannotation.tool.GmtSort;
import com.apps.sannotation.tool.enums.SortType;
import com.apps.sexctption.DataException;
import com.apps.sexctption.NullException;
import com.apps.sutils.StringUtils;
import com.apps.sannotation.constraints.*;
import com.apps.sannotation.identity.GmtCreate;
import com.apps.sannotation.identity.GmtModify;
import lombok.SneakyThrows;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 注解处理工具类
 */
public class AnnotationHelper {

    /**
     * 获取模型不能重复的字段的名称列表
     * @param object
     * @return
     */
    public static Map<String,Object> getModelNoRepeatNames(Object object)
    {
        Map<String,Object> result=new HashMap<>();
        if(null==object)
            throw new NullException("传入对象为空");

        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field item : fields) {
                item.setAccessible(true);
                NoRepeat noRepeat = item.getAnnotation(NoRepeat.class);
                if (null != noRepeat) {
                    if(null == item.get(object))
                        continue;
                    result.put(item.getName(),item.get(object));
                }

            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取被传入注解注解的模型字段的名字
     * @param annotation
     * @param model
     * @return
     */
    public static String getAnnotationFieldName(Class<? extends Annotation> annotation,Class<?> model)
    {
        Assert.notNull(model,"传入对象不能为空");
        List<String> result=new ArrayList<>();
            Field[] fields = model.getDeclaredFields();
            for (Field item : fields) {
                item.setAccessible(true);
                if (null !=  item.getAnnotation(annotation)) {
                    result.add(item.getName());
                }
            }
        if(null == result || result.size()<=0)
            throw new NullException("目标对象不支持按[@"+annotation.getSimpleName()+"]查询");
        if(result.size()>1)
            throw new DataException("一个对象不支持注解多个[@"+annotation.getSimpleName());
        if(StringUtils.isEmpty(result.get(0)))
            throw new NullException("目标对象被注解了[@"+annotation.getSimpleName()+"]字段的属性名不能为空");
        return result.get(0);
    }


    /**
     * 获取模型上排序注解的值
     * @param model
     * @return
     */
    public static SortType getModelGmtSortType(Class<?> model)
    {
        GmtSort sort= model.getAnnotation(GmtSort.class);
        if(null == sort)
            return SortType.NONE;
        else
            return sort.type();
    }
    /**
     * 根据注解验证目标模型的属性是否符合验证规则
     * @param object
     */
    @SneakyThrows
    public static void verifyModelFiled(Object object) {
        if(null==object)
            throw new RuntimeException("传入模型为空");
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field item : fields) {
                item.setAccessible(true);
                String fieldName=item.getName();
                Object obj=item.get(object);

                //非空验证
                NoNull notNull=item.getAnnotation(NoNull.class);
                if(null!=notNull)
                    ValidationHepler.validNoNullAnnotation(fieldName, obj, notNull);
                //字符串长度验证
                StrLen len =item.getAnnotation(StrLen.class);
                if(null != len)
                    ValidationHepler.validStrLenAnnotation(fieldName,obj,len);
                //字符串范围验证
                StrRange strRange =item.getAnnotation(StrRange.class);
                if(null != strRange)
                    ValidationHepler.validStrRangeAnnotation(fieldName,obj,strRange);
                //字符串最小验证
                StrMinLen strMinLen =item.getAnnotation(StrMinLen.class);
                if(null != strMinLen)
                    ValidationHepler.validStrMinLenAnnotation(fieldName,obj,strMinLen);
                //字符串最大验证
                StrMaxLen strMaxLen =item.getAnnotation(StrMaxLen.class);
                if(null != strMaxLen)
                    ValidationHepler.validStrMaxLenAnnotation(fieldName,obj,strMaxLen);
                //字符串必须是数字验证
                StrIsNumber strIsNumber=item.getAnnotation(StrIsNumber.class);
                if(null != strIsNumber)
                    ValidationHepler.validStrIsNumberAnnotation(fieldName,obj,strIsNumber);
                StrEnums strEnums =item.getAnnotation(StrEnums.class);
                if(null != strEnums)
                    ValidationHepler.validStrEnumsAnnotation(fieldName,obj,strEnums);
                //手机号验证
                Mobile mobile=item.getAnnotation(Mobile.class);
                if(null!=mobile)
                    ValidationHepler.validMobileAnnotation(fieldName,obj,mobile);
                //邮箱验证
                Email email=item.getAnnotation(Email.class);
                if(null!=email)
                    ValidationHepler.validEmailAnnotation(fieldName,obj,email);
                //数字范围验证
                NumRange range=item.getAnnotation(NumRange.class);
                if(null!=range)
                   ValidationHepler.validNumRangeAnnotation(fieldName,obj,range);
                //数字最小验证
                NumMin numMin=item.getAnnotation(NumMin.class);
                if(null!=numMin)
                    ValidationHepler.validNumMinAnnotation(fieldName,obj,numMin);
                //数字最大验证
                NumMax numMax=item.getAnnotation(NumMax.class);
                if(null!=numMax)
                    ValidationHepler.validNumMaxAnnotation(fieldName,obj,numMax);
                //小数点最大位数验证
                DecimalMaxLen decimalMaxLen=item.getAnnotation(DecimalMaxLen.class);
                if(null!=decimalMaxLen)
                    ValidationHepler.validDecimalMaxLenAnnotation(fieldName,obj,decimalMaxLen);
                //正则匹配验证
                StrPattern strPattern=item.getAnnotation(StrPattern.class);
                if(null!=strPattern)
                    ValidationHepler.validStrPattenAnnotation(fieldName,obj,strPattern);
                //数字范围验证
                NumLimits numLimits=item.getAnnotation(NumLimits.class);
                if(null!=numLimits)
                    ValidationHepler.validNumLimitsAnnotation(fieldName,obj,numLimits);

            }
    }

    /**
     * 处理模型字段的值
     * @param object
     * @throws IllegalAccessException
     */
    @SneakyThrows
    public static void handleModelFiled(Object object) {

        if(null==object)
            throw new RuntimeException("传入模型为空");
        AutoDefValue autoDefValue=object.getClass().getAnnotation(AutoDefValue.class);
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field item : fields) {
            item.setAccessible(true);
            Object obj=item.get(object);
            //默认数字处理
            NumDef numDef = item.getAnnotation(NumDef.class);
            if (null != numDef && null == obj) {
                //对象为空才设置默认值
                ClassType classType=ClassHelper.getClassType(item);
                if ( classType == ClassType.NUMBER || classType==ClassType.BIGDECIMAL || classType == ClassType.BIGINTEGER) {
                    FieldHelper.InitDefaultValue(item,obj,"",numDef.value());
                }
                else
                    throw new DataException("@NumDef注解只能对float,double,int,BigDecimal使用");
            }
            //默认字符串处理
            StrDef strDef=item.getAnnotation(StrDef.class);
            if (null != strDef && null == obj) {
                if (item.getType().isAssignableFrom(String.class))
                {
                    item.set(object, strDef.value());
                }else
                {
                    throw new DataException("@StrDef注解只能对string使用");
                }
            }
            //为空设置默认值,字段判断类型
            AutoDefValue defValue=item.getAnnotation(AutoDefValue.class);
            if (null != defValue && null == obj) {
                FieldHelper.InitDefaultValue(item,obj,defValue.valString(),defValue.valNumber());
            }
            //处理创建时间字段
            GmtCreate gmtCreate= item.getAnnotation(GmtCreate.class);
            if (null != gmtCreate) {
                if(null==obj) {

                    if(gmtCreate.Cla().isAssignableFrom(LocalDateTime.class))
                        item.set(object, LocalDateTime.now());
                    else if(gmtCreate.Cla().isAssignableFrom(Long.class))
                    {
                        if(gmtCreate.unit() == TimeUnit.SECONDS)
                            item.set(object, System.currentTimeMillis() / 1000);
                        else
                            item.set(object, System.currentTimeMillis());
                    }
                    else if(gmtCreate.Cla().isAssignableFrom(Date.class))
                    {
                        item.set(object, new Date(System.currentTimeMillis()));
                    }else
                        throw new DataException("@GmtCtrate注解只能对long,LocalDateTime使用");
                }
            }
            //处理更新时间
            GmtModify gmtModify=item.getAnnotation(GmtModify.class);
            if(null != gmtModify) {
                if(gmtModify.Cla().isAssignableFrom(LocalDateTime.class)) {
                    item.set(object, LocalDateTime.now());
                }
                else if(gmtModify.Cla().isAssignableFrom(Long.class)) {
                    if(gmtModify.unit() == TimeUnit.SECONDS)
                        item.set(object, System.currentTimeMillis() / 1000);
                    else
                        item.set(object, System.currentTimeMillis());
                }else if(gmtModify.Cla().isAssignableFrom(Date.class))
                {
                    item.set(object, new Date(System.currentTimeMillis()));
                }
                else
                    throw new DataException("@GmtModify注解只能对long,LocalDateTime使用");
            }

            //所有的关于对字段的注解处理完毕后如果模型本身加了AutoDefValue注解则任意字段为空都赋予初始值
            if(null != autoDefValue && null == obj)
                FieldHelper.InitDefaultValue(item,obj,defValue.valString(),defValue.valNumber());

        }
    }

//    /**
//     * 生成模型的缓存key
//     * @param object
//     * @return
//     */
//    @SneakyThrows
//    public static String GenerateCahcheKey(Object object)
//    {
//        String result="";
//        if(null==object)
//            throw new RuntimeException("传入模型为空");
//        Field[] fields = object.getClass().getDeclaredFields();
//        for (Field item : fields)
//        {
//            item.setAccessible(true);
//            Object obj = item.get(object);
//
//            Annotation[] annotation=item.getAnnotations();
//            if(annotation.length>0) {
//                for(int i=0;i<annotation.length;i++)
//                {
//
//                    Identity identity=AnnotationUtils.findAnnotation(annotation[i].getClass(),Identity.class);
//                    if(identity!=null) {
//                        result+=item.getName()+":"+obj.toString();
//                    }
//
//                }
//            }
//
//        }
//        System.out.println(result);
//        return result;
//    }
    /**
     * 获取对象的表名称
     * @param tagetClass
     * @return
     */
    public static String getTabName(Class<?> tagetClass)
    {
        Assert.notNull(tagetClass,"传入对象不能为空");
        TableName tableName=  tagetClass.getAnnotation(TableName.class);
        if(null==tableName)
            throw new RuntimeException("对象不是一个合法的mybits对象,没有@TableName注解");
        return tableName.value();
    }

    /**
     * 处理模型的更新时间字段
     * @param object
     */
    public static void handleModelModifyTimes(Object object)
    {
        Assert.notNull(object,"传入对象不能为空");
        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field item : fields) {
                item.setAccessible(true);
                //处理更新时间
                GmtModify gmtModify=item.getAnnotation(GmtModify.class);
                if(null != gmtModify) {
                    if(item.getClass().isAssignableFrom(LocalDateTime.class))
                        item.set(object, LocalDateTime.now());
                    else if(item.getClass().isAssignableFrom(Long.class)) {
                        if(gmtModify.unit() == TimeUnit.SECONDS)
                            item.set(object, System.currentTimeMillis() / 1000);
                        else
                            item.set(object, System.currentTimeMillis());
                    }
                    return;
                }
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }

    }



    public static void main(String... args)
    {


    }
}
